package cate.game.train.spice;

import cate.common.table.d.GDObj;
import cate.common.table.d.GDOperation;
import cate.common.table.item.SpiceLevelUpRow;
import cate.common.table.item.spice.row.*;
import cate.common.util.GameResult;
import cate.game.GameBody;
import cate.game.client.msg.MergeMsgSender;
import cate.game.event.RoleEventPublisher;
import cate.game.event.hero.HeroPowerChangeEvent;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.res.RewardShow;
import cate.game.role.Role;
import cate.game.role.bag.hero.Hero;
import cate.game.role.bag.spice.Spice;
import cate.game.train.spice.msg.*;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

public class TrainSpiceHandler implements RoleEventPublisher {
    public Hero getHero(Role role, String heroUid){
        return role.getBag().hero.getItem(heroUid);
    }

    /** 获取星格对象，有英雄id从英雄身上取，没有则从背包里取 */
    public Spice getSpice(Role role, String spiceUid) {
        return role.getBag().spice.getItem(spiceUid);
    }

    public void levelUp(Role role, String spiceUid, Set<String> costUids, MixRes consume){
        Spice spice = getSpice(role, spiceUid);
        if (spice == null) {
            role.getGame().notice.message(role, "星格不存在");
            return;
        }
        SpiceBaseRow baseRow = spice.getTpl(role.getGame());
        if (baseRow.quality == 0) {
            role.getGame().notice.message(role, "经验星格无法升级");
            return;
        }
        if (spice.level >= role.getGame().table.spice.exp.getMaxLevelRow(baseRow.quality).level) {
            role.getGame().notice.message(role, "星格已升到最高等级");
            return;
        }
        if (CollectionUtils.isEmpty(costUids) && (consume == null || consume.isEmpty())) {
            role.getGame().notice.message(role, "至少吞噬一个星格");
            return;
        }
        SpiceLevelAttrRow nextAttrRow = role.getGame().table.spice.levelAttr.getAttrRow(spice.tid, spice.level + 1);
        if (nextAttrRow != null && nextAttrRow.needBreak && !spice.broken) {
            role.getGame().notice.message(role, "请突破后再升级");
            return;
        }
        int oldLevel = spice.level;
        // 本次吞噬获得的exp
        int expAdd = 0;
        // 吞噬返还的资源
        MixRes reward = new MixRes();
        // 消耗非经验星格
        if (costUids != null) {
            for (String uid : costUids) {
                Spice costSpice = getSpice(role, uid);
                if (costSpice == null) {
                    role.getGame().notice.message(role, "吞噬的星格不存在");
                    return;
                }
                if (costSpice.onHeroUid != null) {
                    role.getGame().notice.message(role, "无法吞噬装备着的星格");
                    return;
                }
                SpiceBaseRow baseRow1 = costSpice.getTpl(role.getGame());
                if (baseRow1 == null) {
                    role.getGame().notice.message(role, "吞噬的星格有误");
                    return;
                }
                // 获取被吞噬时的资源返还
                expAdd += costSpice.getConsumeExp();
            }
        }
        // 消耗经验星格
        if (consume != null) {
            for (MixResItem item : consume.items) {
                if (item.type != GDObj.Type.PROP) {
                    role.getGame().notice.message(role, "吞噬的经验星格有误");
                    return;
                }
                SpiceLevelUpRow spiceItemRow = role.getGame().table.item.spiceLevelUp.get(item.tid);
                if (spiceItemRow == null) {
                    role.getGame().notice.message(role, "吞噬的经验星格有误");
                    return;
                }
                expAdd += spiceItemRow.value * item.num;
            }
        }
        // 升完级后从背包移除吞噬的命格
        if (consume != null) {
            EcResult<MixResItem> r = consume.consume(role, null);
            if (!r.ok()) {
                role.getGame().notice.message(role, r.message);
                return;
            }
        }
        if (CollectionUtils.isNotEmpty(costUids)) {
            MergeMsgSender sender = new MergeMsgSender();
            for (String uid : costUids) {
                role.getBag().spice.removeItem(uid, sender);
            }
            sender.send(role, true);
        }
        int expMore = spice.addExp(expAdd);
        reward.addList(calRwdByExp(role.getGame(), expMore));
        reward.addAndDialog(role,true,GDOperation.SPICE_LEVEL_UP);
        // 通知星格更新
        role.sendNow(new SpiceUpdateResp(spice));
        role.getGame().notice.message(role, "吞噬成功");
        // 如果升级了英雄身上的星格 则更新战力
        onUpdatePower(role, spice.onHeroUid);
        role.getHistory().action.spiceUpgrade();
        if (spice.level > oldLevel) {
            role.getHistory().action.spiceGetLevel(spice.level, baseRow.quality);
        }
    }

    public void off(Role role, String heroUid, List<Byte> posList){
        Hero hero = getHero(role, heroUid);
        if (hero == null) {
            role.getGame().notice.message(role, "英雄不存在");
            return;
        }
        SpiceOffResp resp = new SpiceOffResp();
        resp.heroUid = heroUid;
        resp.posList = new ArrayList<>();
        EcResult<Byte> r;
        for (Byte pos : posList) {
            r = hero.offSpice(role, pos);
            if (r.ok()) {
                resp.posList.add(r.data);
            } else {
                role.getGame().notice.message(role, r.message);
            }
        }
        role.sendNow(resp);
        role.getHistory().action.spicesOnNum();
        onUpdatePower(role, heroUid);
    }

    public void on(Role role, String spiceUid, String heroUid, byte pos){
        Hero hero = getHero(role, heroUid);
        if(hero == null){
            role.getGame().notice.message(role, "英雄不存在");
            return;
        }
        Spice spice = getSpice(role, spiceUid);
        if(spice == null){
            role.getGame().notice.message(role, "星格不存在");
            return;
        }
        GameResult<Byte> e = hero.onSpice(role.toPlayBuildContext(), spice, pos);
        if(!e.ok()){
            role.getGame().notice.message(role, e);
            return;
        }
        role.getHistory().action.spiceOn();
        role.getHistory().action.spicesOnNum();
        role.sendNow(new SpiceOnResp(spice, heroUid, pos));
        onUpdatePower(role, heroUid);
    }

    public GameResult<Void> breakLevel(Role role, String spiceUid) {
        GameResult<Void> r = new GameResult<>();
        Spice spice = getSpice(role, spiceUid);
        if (spice == null) {
            return r.fail("星格不存在");
        }
        SpiceBaseRow spiceBaseRow = spice.getTpl(role.getGame());
        if (spiceBaseRow == null) {
            return r.fail("星格不存在");
        }
        SpiceBreakRow spiceBreakRow = role.getGame().table.spice.breakLevel.getBreakRow(spiceBaseRow.quality, spice.level);
        if (spiceBreakRow == null || !spiceBreakRow.open || spiceBreakRow.breakLevel == 0) {
            return r.fail("该星格无法突破");
        }
        MixRes consume = new MixRes();
        if (StringUtils.isNotBlank(spiceBreakRow.consumeStr1)) {
            consume.addList(new MixRes(spiceBreakRow.consumeStr1));
        }
        if (StringUtils.isNotBlank(spiceBreakRow.consumeStr2)) {
            consume.addList(new MixRes(spiceBreakRow.consumeStr2));
        }
        if (!consume.isEmpty()) {
            GameResult<MixResItem> consumeRes = consume.consume(role);
            if (!consumeRes.ok()) {
                role.getGame().notice.tipResItem(role, consumeRes.data);
                return r.fail(consumeRes);
            }
        }
        spice.broken = true;
        role.sendNow(new SpiceUpdateResp(spice));
        // 如果升级了英雄身上的星格 则更新战力
        onUpdatePower(role, spice.onHeroUid);
        return r;
    }

    private void onUpdatePower(Role role, String heroUid) {
        if (StringUtils.isNotBlank(heroUid)) {
            role.getBase().updatePower();
            publishEvent(role, new HeroPowerChangeEvent(
                    role, getHero(role,heroUid)));
        }
    }

    /**
     * 根据星格经验返还经验星格
     *
     * @param exp
     * @return
     */
    private MixRes calRwdByExp(GameBody game, int exp) {
        MixRes reward = new MixRes();
        if (exp > 0) {
            List<SpiceLevelUpRow> list = game.table.item.spiceLevelUp.list;
            list.sort(Comparator.comparing(e->-e.value));
            for(SpiceLevelUpRow row : list){
                int bigExpNum = exp / row.value;
                if(bigExpNum > 0){
                    reward.addItem(new MixResItem(GDObj.Type.PROP, row.id, bigExpNum));
                    exp -= row.value * bigExpNum;
                }
            }
        }
        return reward;
    }

    public GameResult<Void> fuseSpice(Role role, List<String> costUids) {
        GameResult<Void> r = new GameResult<>();
        if (costUids == null || costUids.size() != 2) {
            return r.fail("请选择正确的材料");
        }
        Spice spice1 = role.getBag().spice.getItem(costUids.get(0));
        if (spice1 == null) {
            return r.fail("请选择正确的材料");
        }
        Spice spice2 = role.getBag().spice.getItem(costUids.get(1));
        if (spice2 == null) {
            return r.fail("请选择正确的材料");
        }
        if (spice1.level != 10 && spice2.level != 10) {
            return r.fail("请选择正确的材料");
        }
        SpiceFuseRow fuseRow = role.getGame().table.spice.fuse.getFuseRow(spice1.tid, spice2.tid);
        if (fuseRow == null) {
            return r.fail("请选择正确的材料");
        }
        MixRes consume = new MixRes(fuseRow.consumeStr);
        GameResult<MixResItem> consumeRes = consume.consume(role);
        if (!consumeRes.ok()) {
            role.getGame().notice.tipResItem(role, consumeRes.data);
            return r.fail(consumeRes);
        }
        int exp = spice1.getConsumeExp() + spice2.getConsumeExp();
        removeSpice(role, spice1.onHeroUid, spice1.uid);
        removeSpice(role, spice2.onHeroUid, spice2.uid);
        Spice newSpice = new Spice(role, fuseRow.targetTid, 1);
        newSpice.addExp(exp);
        role.getBag().spice.addItem(newSpice, null);

        RewardShow rewardShow = new RewardShow();
        rewardShow.addInsRwd(GDObj.Type.SPICE, newSpice.uid);
        role.getGame().notice.dialog(role, rewardShow);
        role.getHistory().action.spiceFuseTimes(fuseRow.targetTid);
        return r;
    }

    private void removeSpice(Role role, String heroUid, String spiceUid) {
        if (StringUtils.isNotBlank(heroUid)) {
            Hero hero = role.getBag().hero.getItem(heroUid);
            if (hero != null) {
                hero.offSpice(role, spiceUid);
            }
        }
        role.getBag().spice.removeItem(spiceUid, null);
    }

    public GameResult<Void> useLevelItem(Role role, String spiceUid) {
        GameResult<Void> r = new GameResult<>();
        Spice spice = getSpice(role, spiceUid);
        if (spice == null) {
            return r.fail("星格不存在");
        }
        SpiceItemRow item = role.getGame().table.spice.item.list.get(0);
        if (item == null) {
            return r.fail("星格直升瓶不存在");
        }
        SpiceBaseRow spiceBaseRow = spice.getTpl(role.getGame());
        if (spiceBaseRow == null) {
            return r.fail("该星格无法使用直升瓶");
        }
        if (!item.consumes.containsKey(spiceBaseRow.quality)) {
            return r.fail("该星格无法使用直升瓶");
        }
        if (spice.level > item.endLevel || spice.level < item.startLevel) {
            return r.fail("该星格无法使用直升瓶");
        }
        GameResult<MixResItem> consumeRes = new MixRes(GDObj.getMixResStr(GDObj.Type.PROP, item.id, item.consumes.get(spiceBaseRow.quality))).consume(role);
        if  (!consumeRes.ok()) {
            role.getGame().notice.tipResItem(role, consumeRes.data);
            return r.fail(consumeRes);
        }
        spice.level++;
        RewardShow rewardShow = new RewardShow();
        if (spice.exp > 0) {
            MixRes backReward = calRwdByExp(role.getGame(), spice.exp);
            backReward.add(role, true);
            spice.exp = 0;
            rewardShow.addTplRwd(backReward);
        }
        role.sendNow(new SpiceUpdateResp(spice));
        rewardShow.addInsRwd(GDObj.Type.SPICE, spiceUid);
        role.getGame().notice.dialog(role, rewardShow);
        return r;
    }
}
